package bsh.meta;

import java.util.Collection;
import java.util.List;

import org.objectweb.asm.MethodVisitor;

import bsh.BytecodeGenerator;
import bsh.CompilationState;
import bsh.Parameter;
import bsh.asm.acessor.ObjectAccessor;
import bsh.exception.CompilationFailedException;

/**
 * An {@link UnfinishedType} represents a type that is being constructed
 * 
 * @author takeshi
 */
public interface UnfinishedType extends TypeWrapper {

    /**
     * @return the {@link ObjectAccessor} for the field that represents the dynamic fields - {@link #getDynamicsField()}
     */
    ObjectAccessor getDynamicVariablesFieldAccessor();

    /**
     * @return the {@link ObjectAccessor} that has the MathContext - {@link #getMathContextField()}
     */
    ObjectAccessor getMathContextFieldAccessor();

    /**
     * @return the {@link FieldDescriptor} for the dynamic variables
     */
    FieldDescriptor getDynamicsField();

    /**
     * @return the {@link FieldDescriptor} for the math context
     */
    FieldDescriptor getMathContextField();

    /**
     * Adds an {@link UnfinishedInnerType}
     * 
     * @param innerType {@link UnfinishedInnerType}
     */
    void addInnerType(UnfinishedInnerType innerType);

    /**
     * {@inheritDoc}
     */
    Collection<? extends MethodDescriptor> getMethods();

    /**
     * {@inheritDoc}
     */
    FieldDescriptor addField(String name, TypeWrapper type);

    /**
     * Adds a field definition
     * 
     * @param name the field name
     * @param type the field type
     * @param modifiers the field modifiers
     * @return {@link FieldDescriptor} for the newly added field
     */
    FieldDescriptor addField(String name, TypeWrapper type, int modifiers);

    /**
     * {@inheritDoc}
     * 
     * @param options
     */
    FieldDescriptor addStaticField(String name, TypeWrapper type, int options);

    /**
     * {@inheritDoc}
     */
    FieldDescriptor addField(String name, Class<?> type);

    /**
     * {@inheritDoc}
     */
    void addMethod(MethodDescriptor method);

    /**
     * Adds a constructor definition
     * 
     * @param constructorParameters list of parameters of the constructor
     */
    void addConstructor(List<? extends TypeWrapper> constructorParameters);

    /**
     * Adds an empty constructor
     */
    void addEmptyConstructor();

    /**
     * {@inheritDoc}
     */
    int newDynamicInvocationId();

    /**
     * Loads the this object
     * 
     * @param visitor {@link MethodVisitor}
     * @param state {@link CompilationState}
     */
    void loadThis(MethodVisitor visitor, CompilationState state);

    /**
     * @return the string with the source code name.
     */
    String getSourceCodeFileName();

    /**
     * @return the simple name if available
     */
    String simpleName();

    /**
     * Adds a constructor with a body
     * 
     * @param params list of parameters
     * @param bytecodeGenerator the {@link BytecodeGenerator} that will generate the body of the constructor
     */
    void addConstructorWithBody(Parameter[] params, BytecodeGenerator bytecodeGenerator);

    /**
     * @return all of the declared constructors
     */
    Collection<? extends DeclaredConstructor> getUnfinishedConstructors();

    /**
     * Adds a declared field to be written later (in bytecode)
     * 
     * @param variableType the variable type
     * @param name the variable name
     * @param accPublic the access modifiers
     * @return {@link FieldDescriptor}
     */
    FieldDescriptor addDelayedField(TypeWrapper variableType, String name, int accPublic);

    /**
     * @return the {@link FieldDescriptor}
     */
    Collection<? extends FieldDescriptor> getDelayedFields();

    /**
     * Sinalizes that a method has been written on bytecode
     * 
     * @param lineNumber the line number
     * @param methodName the method name
     * @param typeParameters the method parameters
     * @throws CompilationFailedException e
     */
    void writeMethod(int lineNumber, String methodName, List<? extends TypeWrapper> typeParameters) throws CompilationFailedException;

    /**
     * Returns true if the given method signature is already implemented in this type
     * 
     * @param methodName the method name
     * @param typeParameters the type parameters
     * @return boolean
     */
    boolean isMethodImplemented(String methodName, List<? extends TypeWrapper> typeParameters);

}